package com.xyzwps.website.filter;

import com.xyzwps.lib.express.Filter;
import com.xyzwps.lib.express.HttpRequest;
import com.xyzwps.lib.express.HttpResponse;
import com.xyzwps.lib.express.HttpStatus;
import com.xyzwps.lib.express.http.HttpMethod;
import com.xyzwps.lib.openapi.element.*;
import com.xyzwps.lib.openapi.ui.Load;
import com.xyzwps.website.conf.Configurations;
import jakarta.inject.Singleton;

import java.util.List;

@Singleton
public class OpenApiFilter implements Filter {

    private final OpenApi doc;

    public OpenApiFilter(List<OpenApiCustomizer> adders, Configurations config) {
        var info = new Info("xyzwps-website api", "0.0.1"); // TODO: 如何获取 maven 项目的版本号
        this.doc = new OpenApi(info);
        adders.forEach(it -> it.accept(doc));
        doc.addServer(new Server("http://localhost:" + config.getServerPort())
                .description("localhost:" + config.getServerPort()));
    }

    @Override
    public void filter(HttpRequest request, HttpResponse response, Next next) {
        if (request.method() != HttpMethod.GET) {
            next.next(request, response);
            return;
        }

        var path = request.path();
        switch (path) {
            case "/openapi.json" -> {
                response.ok();
                response.headers().set("Content-Type", "application/json");
                var toJsonVisitor = new ToJsonVisitor();
                doc.accept(toJsonVisitor);
                response.send(toJsonVisitor.toCompactString().getBytes());
            }
            case "/openapi.yaml" -> {
                response.ok();
                response.headers().set("Content-Type", "text/yaml");
                var toYamlVisitor = new ToYamlVisitor();
                doc.accept(toYamlVisitor);
                response.send(toYamlVisitor.toYaml().getBytes());
            }
            default -> {
                if (path.startsWith("/swagger-ui/")) {
                    var fileName = path.substring("/swagger-ui/".length());
                    if (fileName.equals("swagger-initializer.js")) {
                        var content = """
                                window.onload = function() {
                                  //<editor-fold desc="Changeable Configuration Block">
                                  window.ui = SwaggerUIBundle({
                                    url: "/openapi.json",
                                    dom_id: '#swagger-ui',
                                    deepLinking: true,
                                    presets: [
                                      SwaggerUIBundle.presets.apis,
                                      SwaggerUIStandalonePreset
                                    ],
                                    plugins: [
                                      SwaggerUIBundle.plugins.DownloadUrl
                                    ],
                                    layout: "StandaloneLayout"
                                  });
                                  //</editor-fold>
                                };
                                """;
                        response.ok();
                        response.headers().set("Content-Type", "text/javascript; charset=utf-8");
                        response.send(content.getBytes());
                    } else {
                        var ext = fileName.substring(fileName.lastIndexOf('.') + 1);
                        var text = Load.load(fileName);
                        if (text == null) {
                            response.status(HttpStatus.NOT_FOUND);
                            response.send(("404 Not Found\n" + text).getBytes());
                        } else {
                            response.ok();
                            switch (ext) {
                                case "css" -> response.headers().set("Content-Type", "text/css");
                                case "js" -> response.headers().set("Content-Type", "text/javascript; charset=utf-8");
                                case "html" -> response.headers().set("Content-Type", "text/html");
                                case "png" -> response.headers().set("Content-Type", "image/png");
                            }
                            response.send(text.getBytes());
                        }
                    }
                } else {
                    next.next(request, response);
                }
            }
        }
    }
}
